Skip to main content

Sharing Characters

Share your characters with other users via long-lived anchors (for physical carriers like NFC tags, QR codes, or print) or short-lived tokens (for one-shot web links). The SDK provides a SharesClient accessible via client.shares.

Overview

Estuary supports two sharing models:

  • Share anchors — Long-lived, owner-scoped redirectors that mint a fresh short-lived session token on every redemption. Intended for physical carriers (NFC tags, QR codes, print). Unlimited redemptions by default; protected by per-anchor rate limits and dashboard revocation.
  • Share tokens — Short-lived one-shot links with built-in redemption caps. Intended for web links.

Both models issue a short-lived session token (sst_...) that a recipient can use to connect to the character through any Estuary SDK.

Authentication

The SharesClient is available immediately on EstuaryClient (no connect() required):

from estuary_sdk import EstuaryClient, EstuaryConfig

config = EstuaryConfig(api_key="est_...")
client = EstuaryClient(config)

# client.shares is ready to use
result = await client.shares.create_anchor(character_id="char_abc")
Authentication requirements

Most SharesClient methods require a Firebase ID token on the backend. Only the three methods below are reachable with a standard est_ API key:

  • create_anchor — create a long-lived anchor for a character you own
  • open_anchor — redeem an anchor to get a session token (unauthenticated)
  • exchange_share_token — redeem a share token to get a session token (unauthenticated)

All other methods (list, revoke, create share token) will raise EstuaryError with HTTP 401 if called with API-key-only auth.

Creating an Anchor

Create a long-lived anchor for a character you own. The returned anchorUrl is stable and safe to burn onto an NFC tag, encode in a QR code, or print.

result = await client.shares.create_anchor(
character_id="char_abc",
memory_sharing="isolated", # "isolated" or "shared"
max_interactions=None, # None = no cap
)

print(result["id"]) # 32-char url-safe anchor id
print(result["anchorUrl"]) # https://share.estuary-ai.com/sa/{id}
ParameterTypeDefaultDescription
character_idstrrequiredThe character being shared
memory_sharingstr"isolated""isolated" (each visitor has private memory) or "shared" (all visitors share the owner's memory)
max_interactionsint | NoneNoneOptional per-session interaction cap
caution

Creating an anchor counts against a per-user cap. If you exceed the cap, the call raises EstuaryError with HTTP 429.

Redeeming an Anchor

When a visitor scans or taps an anchor URL, the client resolves it into a fresh session token by calling open_anchor. This endpoint is unauthenticated and rate limited per anchor.

redeemed = await client.shares.open_anchor(anchor_id="abc123...")

session_token = redeemed["sessionToken"] # sst_...
character_id = redeemed["characterId"]
player_id = redeemed["playerId"]
character = redeemed["character"] # id, name, tagline, avatar, modelUrl, ...

The returned sessionToken is a short-lived (~1 hour) token you can pass to EstuaryConfig to connect as the visitor:

visitor_config = EstuaryConfig(session_token=redeemed["sessionToken"])
async with EstuaryClient(visitor_config) as visitor:
await visitor.connect()
await visitor.send_text("Hello!")

Exchanging a Share Token

For short-lived one-shot web links, use exchange_share_token instead. This endpoint is also unauthenticated.

exchanged = await client.shares.exchange_share_token(
token="shr_...",
recipient_id="visitor-local-id-123", # required for isolated shares
)

session_token = exchanged["sessionToken"]
ParameterTypeDescription
tokenstrThe share token string
recipient_idstr | NoneClient-provided recipient identifier. Required for isolated shares; may be omitted for shared mode.
note

Unlike open_anchor, the exchange_share_token response does not include a top-level memorySharing field.

Share Management (Firebase Auth)

The following methods require a Firebase ID token on the backend. They exist for API completeness but will raise EstuaryError(401) with API-key-only auth.

MethodDescription
list_anchors(character_id=None)List non-revoked anchors owned by the caller, optionally filtered by character
revoke_anchor(anchor_id)Soft-delete an anchor and kill all active sessions that depended on it
bulk_revoke_anchors_by_api_key(api_key_id)Revoke every anchor minted by a given API key. Primary use case: recovering from a compromised device
create_share_token(character_id, ttl, memory_sharing, max_exchanges)Create a short-lived share token (ttl one of "24h" | "7d" | "30d" | "90d")
list_character_shares(character_id)List active share tokens for a character
revoke_share_token(share_token_id)Revoke a share token by its database row id

Anchors vs Tokens

PropertyShare anchorShare token
Intended useNFC tags, QR codes, printOne-shot web links
LifetimeLong-livedShort-lived (TTL)
RedemptionsUnlimited (rate limited)Capped by max_exchanges
Revocable from dashboardYesYes
Reachable with API keycreate_anchor, open_anchorexchange_share_token only

For long-lived, transport-neutral redirectors, use share anchors. For short-lived one-shot links, use share tokens.