Skip to main content

afini-twin-sdk

Official Python SDK for the AfiniTwin B2B API.

The AfiniTwin is a portable cognitive profile (Big Five + 5 supplementary layers) built on the Afini.ai platform. This SDK gives you typed access to a user's snapshot from your own systems — CRMs, custom assistants, internal pipelines.

Installation

pip install afini-twin-sdk

Requires Python ≥ 3.10. Built on httpx and pydantic v2.

Get an API key

Active users with a Professional plan on Afini.ai can generate keys at afini.ai/dashboard/twin/api. The key is shown once — store it securely.

Quick start

Async

import asyncio
import os
from afini_twin import AfiniTwinClient

async def main():
    async with AfiniTwinClient(api_key=os.environ["AFINITWIN_KEY"]) as client:
        me = await client.me()
        print(f"User has {me['twins']['ready']} ready snapshots; quota {me['quota']['remaining']}/{me['quota']['monthlyLimit']}")

        snapshots = await client.historic()
        for s in snapshots["snapshots"]:
            print(s["id"], s["snapshotDate"])

        # Download standard preset as Markdown
        md = await client.preset("estandar", format="md", lang="es")
        print(md[:200], "…")

asyncio.run(main())

Sync

from afini_twin import AfiniTwinSyncClient

with AfiniTwinSyncClient(api_key=os.environ["AFINITWIN_KEY"]) as client:
    me = client.me()

Sending data into the user's profile (twin:write scope)

If your API key has the twin:write scope, you can seed life-facts and annotations. They go to the user's review queue at /dashboard/discoveries; nothing is injected into the profile until the user approves.

from afini_twin import AfiniTwinClient, LifeFactInput

async with AfiniTwinClient(api_key=os.environ["AFINITWIN_KEY"]) as client:
    result = await client.life_facts_create([
        LifeFactInput(
            category="professional",
            value="Trabaja en una startup de IA en Bilbao desde 2023",
            valence="positive",
            consent=True,
            external_ref="crm-12345",
        )
    ])
    print(result["accepted"], "candidates queued ->", result["inboxUrl"])

For free-form notes:

from afini_twin import AnnotationInput

await client.annotations_create([
    AnnotationInput(tag="observation", text="Mostró interés por escalar a Pro", consent=True)
])

The pydantic models reject consent != True at validation time — you can't accidentally submit without an explicit confirmation.

Verifying webhook signatures

Every webhook POST carries an X-AfiniTwin-Signature: sha256=<hmac> header. Verify before trusting the payload:

FastAPI

from fastapi import FastAPI, Request, HTTPException
from afini_twin import verify_webhook_signature

app = FastAPI()
SECRET = os.environ["AFINITWIN_WEBHOOK_SECRET"]

@app.post("/webhooks/afinitwin")
async def afinitwin_hook(request: Request):
    raw = await request.body()
    sig = request.headers.get("x-afinitwin-signature")
    if not verify_webhook_signature(raw, sig, SECRET):
        raise HTTPException(403)
    payload = await request.json()
    if payload["event"] == "twin.snapshot.ready":
        # … pull the new snapshot
        pass
    elif payload["event"] == "twin.quota.exceeded":
        # … alert your billing
        pass
    return {"ok": True}

Django / Flask

The function is framework-agnostic: pass the raw body (bytes or str) plus the header value plus the secret.

Error handling

from afini_twin import AfiniTwinClient, AfiniTwinApiError

try:
    async with AfiniTwinClient(api_key=key) as client:
        await client.me()
except AfiniTwinApiError as e:
    if e.status == 429 and e.body and e.body.get("code") == "TIER_QUOTA_EXCEEDED":
        # upgrade your B2B tier
        ...
    raise

Rate limits

Endpoint group Per minute Per month
/health 120 unlimited
/me, /historic, /snapshots/*, /preset/* 60 per tier
/life-facts, /annotations 30 per tier

The monthly cap is enforced per user across all keys based on the B2B tier (Included = 10k, Starter = 100k, Pro = 1M, Enterprise = custom).

License

MIT © Bilbao AI S.L.

Release files for afini-twin-sdk 0.1.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 afini-twin-sdk 0.1.0
File Size Uploaded
afini_twin_sdk-0.1.0.tar.gz 7.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for afini-twin-sdk 0.1.0
File Interpreter ABI Platform
afini_twin_sdk-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 16.6 kB

Release files / afini_twin_sdk-0.1.0.tar.gz

Download URL afini_twin_sdk-0.1.0.tar.gz
Size 7.5 kB
Tags Source
SHA-256 checksum
How to use checksums
09fb43a17e1afd5b74b94f91ead7d614d3d1b09d616e0eaf1e22f961a5b4bcc5
BLAKE2b-256 checksum
How to use checksums
ffb413f0bc8eac420a03179e41607a1a9912ade37333f5f050455d0109786950
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Release files / afini_twin_sdk-0.1.0-py3-none-any.whl

Download URL afini_twin_sdk-0.1.0-py3-none-any.whl
Size 9.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6f051c8be9c77beb9f2554a0c75a7168ca883e64fb666e2acc3f83a4fb373636
BLAKE2b-256 checksum
How to use checksums
9d1707aec4f9f4f4757cd44f39b61587096102b36f1221bc40686c980d090f10
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Release history Release notifications | RSS feed

This release

0.1.0 This release

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