Python SDK
The official Python library for the RSFlowHub AI API, with sync and async clients. Add sentiment analysis, translation, chat, PII redaction, knowledge-base search and chatbots to Django, FastAPI, Flask, Celery jobs, scripts and notebooks.
Direct System Definition: RSFlowHub Python SDK
rsflowhub is the official PyPI package for RSFlowHub. Install it with pip install rsflowhub, set RSFLOWHUB_API_KEY and call any API as client.ai.slug_in_snake_case(...). It supports Python 3.9+, has a sync RSFlowHub and an async AsyncRSFlowHub client built on httpx, typed method stubs for mypy and Pyright, typed errors by error code and automatic retries for 429 and 5xx answers. New APIs work without updating the package.
| Package | rsflowhub on PyPI |
|---|---|
| Install | pip install rsflowhub |
| Requires | Python 3.9 or newer, httpx |
| Works with | Django, FastAPI, Flask, Celery, scripts and notebooks |
| Source | github.com/RSFlowHub/rsflowhub-python (MIT license) |
Install
pip install rsflowhub
# poetry add rsflowhub · uv add rsflowhub
Create an API key in your dashboard and put it in your environment. The SDK reads RSFLOWHUB_API_KEY automatically, or you can pass api_key=.
export RSFLOWHUB_API_KEY=rfh_your_api_key
Make your first call
from rsflowhub import RSFlowHub
client = RSFlowHub() # reads RSFLOWHUB_API_KEY, or RSFlowHub(api_key="rfh_...")
res = client.ai.sentiment_analysis(
text="Setup took two minutes and support answered right away.",
)
print(res.result["sentiment"]) # "positive"
print(res.result) # the whole AI output
print(res.request_id) # "req_..." quote it when you contact support
Async client
AsyncRSFlowHub has exactly the same methods; each returns an awaitable. Use it in FastAPI, aiohttp, Django async views or anywhere you run several calls at once.
import asyncio
from rsflowhub import AsyncRSFlowHub
async def main() -> None:
async with AsyncRSFlowHub() as client:
# run several calls at the same time
sentiment, summary = await asyncio.gather(
client.ai.sentiment_analysis(text=review),
client.ai.text_summarize(text=review, length="short"),
)
print(sentiment.result["sentiment"], summary.result)
asyncio.run(main())
The response object
Every successful call returns a read-only rsflowhub.Response built from the API envelope {success, request_id, data, meta}. AI endpoints put their output in data.result.
| Use | What you get |
|---|---|
res.result | The AI output (data.result), or data when there is no result (knowledge bases, chatbots) |
res.data, res["key"], dict(res) | Anything under data (the response is a read-only mapping) |
res.get_path("result.aspects.0.name", default) | One value, with dot notation |
res.request_id, res.meta | Server request id and {version, timestamp} |
res.status_code, res.headers | HTTP status and headers |
res.rate_limit | {"limit", "remaining", "reset"} from the X-RateLimit-* headers |
Calling any API
Methods are not hard-coded. The method is the endpoint's slug in snake_case, grouped by resource: client.ai, client.knowledge_bases, client.chatbots, client.faq_collections and client.account. See every endpoint in the API reference.
# The method name is the endpoint slug in snake_case (camelCase also works)
client.ai.translation(text="Hello", target_language="French")
client.ai.pii_redaction(text="Call me on 555-0100")
client.ai.ticket_analyze(ticket="My order never arrived")
# The body can also be one dict
client.ai.chat({"message": "Hi!"})
# An AI API released after you installed the SDK works the same way
client.ai.brand_new_endpoint(text="...")
client.call("ai", "brand_new_endpoint", text="...")
# A resource the SDK does not know yet
client.resource("webhooks").list()
# Any route: method, path, body, query
usage = client.request("GET", "/account/usage", query={"page": 2})
Path ids and file uploads
from pathlib import Path
# Ids in the URL come first, then the body
client.knowledge_bases.ask(12, question="Refund policy?")
client.chatbots.get_conversation(3, "conv_abc123")
# ...or by name
client.knowledge_bases.ask(id=12, question="Refund policy?")
# A pathlib.Path, bytes or an open binary file makes it a file upload
client.knowledge_bases.create_document(
12,
file=Path("refund-policy.pdf"),
metadata={"source": "help-center"}, # sent as metadata[source]
)
Knowledge bases (RAG) and chatbots
Build a searchable help center from your documents and FAQs, then answer questions from it or run a chatbot on top of it.
from pathlib import Path
# 1. A knowledge base for your help center
kb = client.knowledge_bases.create(name="Help center")
kb_id = kb.get_path("knowledge_base.id")
# 2. Add content: a document, or a single FAQ item
client.knowledge_bases.create_document(kb_id, file=Path("refund-policy.pdf"))
client.knowledge_bases.create_item(
kb_id,
content="How long do refunds take?",
answer="Refunds reach your card in 5 to 7 business days.",
)
# 3. Ask questions grounded in that content
answer = client.knowledge_bases.ask(kb_id, question="When will I get my money back?")
print(answer.result)
# A chatbot (created in the dashboard or with client.chatbots.create(...))
reply = client.chatbots.send_message(chatbot_id, message="Where is my order?")
conversation_id = reply["conversation_id"]
Errors
Every API error is raised as an rsflowhub.APIError subclass chosen by the error code in the error envelope, with status_code, code, message, details and request_id. Everything extends rsflowhub.RSFlowHubError.
import rsflowhub
try:
client.ai.text_summarize(text=article)
except rsflowhub.ValidationError as e:
print(e.errors) # {"text": ["The text field is required."]}
except rsflowhub.InsufficientCreditsError as e:
print(e.required_credits, e.available_credits)
except rsflowhub.RateLimitError as e:
print(e.retry_after) # already retried max_retries times
except rsflowhub.APIError as e:
print(e.status_code, e.code, e.message, e.request_id)
except rsflowhub.APIConnectionError:
print("network problem or timeout") # APITimeoutError is a subclass
| Exception | Status | Error codes | Extra |
|---|---|---|---|
AuthenticationError | 401 | API_KEY_MISSING, INVALID_API_KEY | |
InsufficientCreditsError | 402 | INSUFFICIENT_CREDITS | required_credits, available_credits |
PermissionDeniedError | 403 | SPENDING_LIMIT_REACHED, USER_INACTIVE | |
NotFoundError | 404 | ENDPOINT_NOT_FOUND | |
ValidationError | 422 | VALIDATION_ERROR | errors |
RateLimitError | 429 | RATE_LIMIT_EXCEEDED | retry_after |
InternalServerError | 500 | INTERNAL_SERVER_ERROR | |
ServiceUnavailableError | 502 / 503 | AI_PROVIDER_ERROR, PROVIDER_UNAVAILABLE | |
APIConnectionError / APITimeoutError | none | Network failure / too slow |
Options, retries and timeouts
429, 502, 503, 504 and network failures are retried twice with backoff, respecting Retry-After; those answers are never charged. Other errors are raised at once. Limits and the credit formula are on Rate limits & credits. Create one client and reuse it; it is safe to share across threads.
client = RSFlowHub(
api_key="rfh_...", # default: RSFLOWHUB_API_KEY
base_url="https://rsflowhub.com/api/v1", # default: RSFLOWHUB_BASE_URL
timeout=60.0, # seconds per attempt
max_retries=2, # for 429, 502, 503, 504 and network errors
default_headers={}, # extra headers on every request
http_client=None, # your own httpx.Client (proxies, event hooks, tests)
live_spec=True, # look up unknown non-AI methods in the OpenAPI document
)
# Per call
client.ai.chat(message="Hi", timeout=10, max_retries=0, extra_headers={"X-Trace": "abc"})
res.rate_limit # {"limit": 60, "remaining": 59, "reset": None}
FastAPI, Django, Flask and Celery
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import rsflowhub
from rsflowhub import AsyncRSFlowHub
client = AsyncRSFlowHub()
@asynccontextmanager
async def lifespan(app: FastAPI):
yield
await client.aclose()
app = FastAPI(lifespan=lifespan)
class Comment(BaseModel):
text: str
@app.post("/moderate")
async def moderate(comment: Comment):
try:
res = await client.ai.comment_moderate(comment=comment.text)
except rsflowhub.ValidationError as e:
raise HTTPException(422, detail=e.errors)
except rsflowhub.APIError as e:
raise HTTPException(e.status_code, detail=e.message)
return res.result
# views.py (settings.py: RSFLOWHUB_API_KEY = env("RSFLOWHUB_API_KEY"))
import json
from django.conf import settings
from django.http import JsonResponse
from django.views.decorators.http import require_POST
import rsflowhub
from rsflowhub import RSFlowHub
client = RSFlowHub(api_key=settings.RSFLOWHUB_API_KEY) # once, reused by every request
@require_POST
def ask_help_center(request):
question = json.loads(request.body)["question"]
try:
res = client.knowledge_bases.ask(settings.HELP_CENTER_KB_ID, question=question)
except rsflowhub.APIError as e:
return JsonResponse({"error": e.message}, status=e.status_code)
return JsonResponse(res.data)
from flask import Flask, jsonify, request
import rsflowhub
from rsflowhub import RSFlowHub
app = Flask(__name__)
client = RSFlowHub()
@app.post("/summarize")
def summarize():
try:
res = client.ai.text_summarize(text=request.json["text"], format="bullet_points")
except rsflowhub.APIError as e:
return jsonify(error=e.message, code=e.code), e.status_code
return jsonify(res.result)
# tasks.py: long or bulk work belongs in a background task
from celery import shared_task
import rsflowhub
from rsflowhub import RSFlowHub
client = RSFlowHub()
# Retry only errors that are never charged (network, AI temporarily down)
@shared_task(
autoretry_for=(rsflowhub.APIConnectionError, rsflowhub.ServiceUnavailableError),
retry_backoff=True,
max_retries=3,
)
def triage_ticket(ticket_id: int) -> None:
ticket = Ticket.objects.get(pk=ticket_id)
analysis = client.ai.ticket_analyze(ticket=ticket.body).result
ticket.priority = analysis["priority"]
ticket.department = analysis["suggested_department"]
ticket.save(update_fields=["priority", "department"])
Type hints and staying up to date
- New AI APIs work at once: they are called by name, no upgrade needed.
- Other new routes are looked up in the public OpenAPI document the first time you call them.
- Type hints: the package ships typed stubs (
py.typed) with every method's keyword arguments andLiteralchoices, so mypy, Pyright and your editor catch mistakes early. They are regenerated weekly;pip install -U rsflowhubpicks them up. - The full method list is in docs/ENDPOINTS.md.
Related
- All official SDKs and how they stay up to date
- Error codes and rate limits & credits
- Authentication & API keys
- OpenAPI document (every request and response)
- Examples repository
- RSFlowHub PHP SDK (
composer require rsflowhub/rsflowhub-php) - RSFlowHub JavaScript & TypeScript SDK (
npm install rsflowhub)