FluidTalk Characters — Python SDK
Official Python SDK for the FluidTalk Characters API — drive an AI persona across DMs, comments, triggers, and follow-ups from your own bot or connector.
Install
pip install fluidtalk
Quickstart
from fluidtalk import FluidTalk
ft = FluidTalk(token="ftc_live_...") # base_url defaults to production
# A lead DM'd the character — get the reply and send the bubbles yourself.
reply = ft.chat(platform="instagram", handle="mark", message="hey ava")
for bubble in reply.bubbles:
send_dm("mark", bubble.text) # your platform I/O
print("session:", reply.session_id)
Your per-character connector token (ftc_live_…) is sent as X-Connector-Token; get it from the character's platform settings in the dashboard. The token is the character — you name the platform in each call.
API
| Method | Endpoint |
|---|---|
ft.chat(platform, handle, message="", image_url=None, session_id=None, own_username=None) |
POST /chat |
ft.event(platform, handle, external_event_id, event_type="purchase", amount=None, currency=None) |
POST /events |
ft.trigger(platform, handle, event_id, external_event_id, context=None, own_username=None) |
POST /triggers — event_id="outreach" fires the built-in Cold Outreach entry |
ft.followups.list(platform, own_username=None, limit=100) |
GET /followups |
ft.followups.ack(followup_id) |
POST /followups/{id}/ack |
ft.comment(platform, post_ref, caption=None, image_urls=None, author_handle=None) |
POST /comments |
ft.comment_reply(platform, post_ref, replier_handle, reply_text="", parent_comment_ref=None) |
POST /comments/reply |
ft.comment_engage(platform, post_ref, thread, post=None, target_comment_ref=None) |
POST /comments/engage — join a thread between other people |
ft.comment_media(platform, post_ref, data, filename=None, content_type=None) |
POST /comments/media |
ft.inbound_media(platform, data, filename=None, content_type=None) |
POST /inbound-media |
comment_engage is the third comment motion: joining a conversation between other people,
under a post the character may never have touched. You must send thread — we have no rows for
comments we never saw, so it is the character's only context. Omit target_comment_ref and the
character picks the comment worth answering, or abstains. Abstaining is the normal outcome, not
an error — branch on reply, never on the call having succeeded:
res = ft.comment_engage(platform="instagram", post_ref="p1", thread=[
{"comment_ref": "c1", "author_handle": "dan", "text": "silicone will fill a half-inch gap fine"},
{"comment_ref": "c2", "author_handle": "mark", "text": "will it though?", "parent_ref": "c1"},
])
if res.reply: # None on every skip
post_reply(res.target_comment_ref, res.reply) # your platform I/O
else:
print("abstained:", res.reason) # no_target_selected, thread_too_deep, …
comment_media rehosts a post's image so the character can actually see it. We do not fetch
that image — the model provider does — so a public URL is not enough; the host has to serve the
provider's fetcher, and plenty of genuinely public ones do not (Wikimedia renders in a browser and
comes back vision_failed). Bytes in, a URL for comment's image_urls out. Not billed.
up = ft.comment_media(platform="instagram", post_ref="p1", data=raw_bytes, filename="post.jpg")
ft.comment(platform="instagram", post_ref="p1", caption="new deck", image_urls=[up.url])
inbound_media is for a lead-sent photo you only have the bytes of — a Telegram
file_id you downloaded, or an Instagram CDN URL that is signed and expires. You pass
raw bytes, it returns a permanent url to hand to chat as image_url. Already have a
publicly-fetchable URL? Skip it and pass that straight to chat.
up = ft.inbound_media(platform="instagram", data=raw_bytes, filename="photo.jpg")
ft.chat(platform="instagram", handle="mark", message="what do you think? 😏", image_url=up.url)
Responses are returned as attribute-access objects unwrapped from the {data, request_id} envelope (reply.bubbles[0].text, res.decision); a missing field reads as None. Use .to_dict() for the raw dict.
Errors
Every non-2xx response raises a typed exception (all subclass FluidTalkError / ApiError):
from fluidtalk import FluidTalk, PaymentRequiredError, RateLimitError, ApiError
ft = FluidTalk(token="ftc_live_...")
try:
reply = ft.chat(platform="instagram", handle="mark", message="hi")
except PaymentRequiredError:
top_up_wallet() # 402 — the wallet can't cover the turn
except RateLimitError:
backoff_and_retry() # 429
except ApiError as e:
print(e.status, e.code, e.request_id, e.message)
AuthError (401), PaymentRequiredError (402), PermissionError (403), NotFoundError (404), ConflictError (409), ValidationError (422), RateLimitError (429), and ApiError (anything else).
Configuration
FluidTalk(
token="ftc_live_...",
base_url="https://api-talk.fluidvip.com", # green: https://api-green-talk.fluidvip.com
timeout=60.0,
)
Development
pip install -e ".[dev]"
pytest
Metadata
Release files for fluidtalk 2.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fluidtalk-2.6.0.tar.gz | 15.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fluidtalk-2.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 27.9 kB
Release files / fluidtalk-2.6.0.tar.gz
| Download URL | fluidtalk-2.6.0.tar.gz |
|---|---|
| Size | 15.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
67912c303fd7aff4a95108c4dbfbcaf9b00f61a7bb37fd4a8ef89f414f473507
|
|
BLAKE2b-256 checksum How to use checksums |
982c3ed2bd79da1e21c11dda7be50b74c543b7529bd4467fc28bdf724cfa84b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.11
|
Release files / fluidtalk-2.6.0-py3-none-any.whl
| Download URL | fluidtalk-2.6.0-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
16f29cd6425583177d12899718873a2102047b7ff2f8ceca760930f71253bd05
|
|
BLAKE2b-256 checksum How to use checksums |
9248a155cad1b1c6c3a66c02d3c403f060099b846035c63d751f315c4f3de140
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.11
|
Security for fluidtalk 2.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.