Skip to main content

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

Release files for fluidtalk 2.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fluidtalk 2.5.0
File Size Uploaded
fluidtalk-2.5.0.tar.gz 15.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fluidtalk 2.5.0
File Interpreter ABI Platform
fluidtalk-2.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 27.4 kB

Release files / fluidtalk-2.5.0.tar.gz

Download URL fluidtalk-2.5.0.tar.gz
Size 15.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0850b77910f5f3a62c8de9370a52f7a46fae6da5d3592414a375040fc9b132dc
BLAKE2b-256 checksum
How to use checksums
0f11135a2e7ac53d6e450aeb1ff3257f2f519dc94bc83db92d11424ccb7bfb29
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.5.0-py3-none-any.whl

Download URL fluidtalk-2.5.0-py3-none-any.whl
Size 12.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
07234bdf72e8a968942cf556438d2240a21afe1de67daaa7219fd313fafbdb32
BLAKE2b-256 checksum
How to use checksums
002ffbeeb74cd1c70862e7f8ce86e1cfd1819bf82fe136fac71c2b280342005e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.11

Release history Release notifications | RSS feed

This release

2.5.0 This release

2 release files

2.4.0

2 release files

2.3.0

2 release files

2.2.0

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release 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