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.3.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.3.0
File Size Uploaded
fluidtalk-2.3.0.tar.gz 13.9 kB Details

Built distribution (wheel)

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

Total release size: 25.5 kB

Release files / fluidtalk-2.3.0.tar.gz

Download URL fluidtalk-2.3.0.tar.gz
Size 13.9 kB
Tags Source
SHA-256 checksum
How to use checksums
7a6ef15ce906fa20adbbd58a874e029e2f8e418d08b6cafb42ecc453358f88b3
BLAKE2b-256 checksum
How to use checksums
fa4a665057a80db379479a6e9f7d61f01aad319b862b457c2d29b09641cc93d8
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.3.0-py3-none-any.whl

Download URL fluidtalk-2.3.0-py3-none-any.whl
Size 11.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
883c48efcbee675df211e4ec3c7220d3b843a1298d5f23df95f5ef7cc40ec46c
BLAKE2b-256 checksum
How to use checksums
26396c0281c8f35a0ebbebdc807d3dab46cd2d7eed9476446087a5daed94608f
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

2.4.0

2 release files

This release

2.3.0 This release

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