SynAuth SDK
Python SDK for AI agents to request human-approved actions. Two approval methods: TOTP (any authenticator app) or Face ID (SynAuth iOS app).
Install
pip install synauth
Two Ways to Get Started
Option A: TOTP (No iOS App Required)
Use any TOTP authenticator (Google Authenticator, Authy, Apple Passwords, 1Password). Time to first approval: ~5 minutes.
from synauth import SynAuthAdmin, SynAuthClient
# 1. Create account via magic link
result = SynAuthAdmin.request_magic_link("you@example.com")
# 2. Verify and register your device
device = SynAuthAdmin.verify_magic_link(result["token"], "My Laptop")
admin = SynAuthAdmin(device_id=device["device_id"])
# 3. Set up TOTP — scan the QR code with your authenticator app
setup = admin.totp_setup()
print(f"Add to authenticator: {setup['provisioning_uri']}")
# 4. Verify TOTP with a code from your authenticator
admin.totp_verify("123456") # replace with actual code
# 5. Create an API key for your agent
key = admin.create_key("my-agent", "Research Agent")
print(f"API key (save this!): {key['key']}")
Option B: Face ID (iOS App)
- Get the SynAuth iOS app from the App Store. Create an account.
- Copy your API key from the app — it starts with
aa_.
Quick Start — Agent Side
from synauth import SynAuthClient
client = SynAuthClient(api_key="aa_your_key_here")
# Agent requests approval for an action
result = client.request_action(
action_type="communication",
title="Send quarterly report",
description="Email to investor@example.com with Q4 results",
risk_level="low",
)
# Agent waits for human approval (TOTP or Face ID)
status = client.wait_for_result(result["id"])
if status["status"] == "approved":
send_email(...)
Approving Actions with TOTP
from synauth import SynAuthAdmin
admin = SynAuthAdmin(device_id="dev_your_device_id")
# See what's pending
pending = admin.get_pending()
for action in pending["actions"]:
print(f"{action['id']}: {action['title']}")
# Approve with your TOTP code
admin.approve("action_id_here", totp_code="123456")
# Or deny
admin.deny("action_id_here", reason="Not authorized")
How It Works
- Your AI agent calls
request_action()(or a convenience method likerequest_email()) - The action goes pending on SynAuth
- You approve via TOTP code or Face ID on your iPhone
- The agent polls for the result — or receives a webhook callback
- If using the credential vault, SynAuth executes the action with stored credentials
API Key Management
admin = SynAuthAdmin(device_id="dev_your_device_id")
# Create keys for your agents
key = admin.create_key("trading-agent", "Trading Bot")
# List active keys (values hidden — only prefixes)
keys = admin.list_keys()
for k in keys["keys"]:
print(f"{k['key_prefix']} — {k['name']} ({k['agent_id']})")
# Revoke a compromised key
admin.revoke_key("aa_abc12")
TOTP Management
admin = SynAuthAdmin(device_id="dev_your_device_id")
# Check TOTP status
status = admin.totp_status()
print(f"TOTP enabled: {status['enabled']}")
# Reset TOTP (delete and re-setup)
admin.totp_delete()
setup = admin.totp_setup()
admin.totp_verify("654321")
Credential Vault
The agent can't bypass what it can't access. Store your API credentials in SynAuth's vault. The agent requests actions through the SDK — SynAuth injects the real credentials after approval. The agent never sees your API keys.
# Discover available services
services = client.list_vault_services()
# Execute an API call through the vault (approval-gated)
result = client.execute_api_call(
service_name="openai",
method="POST",
url="https://api.openai.com/v1/chat/completions",
body='{"model": "gpt-4", "messages": [{"role": "user", "content": "Hello"}]}',
)
Convenience Methods
# Email
client.request_email(recipient="team@co.com", subject="Update", preview="Q4 numbers")
# Purchase
client.request_purchase(amount=49.99, merchant="DigitalOcean", description="3x droplets")
# Booking
client.request_booking(title="Team lunch", description="12pm at Nobu", amount=850.00)
# Social media
client.request_post(platform="Twitter", content_preview="Announcing our Series A...")
# Data access
client.request_data_access(resource="production-db", reason="Monthly analytics export")
# Legal
client.request_contract(title="NDA with Acme Corp", description="Standard mutual NDA")
Payment-Only Wrapper
For agents that only need payment authorization:
from synauth.pay import SynPayClient
client = SynPayClient(api_key="aa_your_key_here")
request = client.request_payment(
amount=29.99,
merchant="OpenAI",
description="GPT-5 API credits",
)
status = client.wait_for_result(request["id"])
Error Handling
from synauth import (
SynAuthClient,
SynAuthError,
SynAuthAPIError,
RateLimitError,
ActionDeniedError,
ActionExpiredError,
VaultExecutionError,
)
client = SynAuthClient(api_key="aa_...")
try:
result = client.execute_api_call(
service_name="github",
method="POST",
url="https://api.github.com/repos",
body='{"name": "new-repo"}',
)
except ActionDeniedError as e:
print(f"User denied: {e.reason}")
except ActionExpiredError as e:
print(f"Request expired: {e.request_id}")
except RateLimitError:
print("Rate limited — back off and retry")
except VaultExecutionError as e:
print(f"Vault execution failed: {e.detail}")
except SynAuthAPIError as e:
print(f"API error {e.status_code}: {e.detail}")
Spending Limits
Check your agent's spending against configured limits before making purchases:
summary = client.get_spending_summary()
for s in summary["summaries"]:
print(f"{s['action_type']} ({s['period']}): ${s['spent']:.2f} / ${s['limit']:.2f}")
History
Review past action requests:
history = client.get_history(limit=10, status="approved")
for action in history["actions"]:
print(f"{action['title']} — {action['status']}")
Webhook Callbacks
Receive status updates without polling:
result = client.request_action(
action_type="purchase",
title="Buy API credits",
amount=100.00,
callback_url="https://your-server.com/webhook/synauth",
)
# SynAuth will POST to callback_url when the user approves or denies
Action Types
| Type | Examples | Default Risk |
|---|---|---|
communication |
Emails, messages, notifications | low |
purchase |
Buying, subscriptions, payments | medium |
scheduling |
Bookings, reservations, calendar | low |
legal |
Contracts, terms, agreements | critical |
data_access |
Database queries, file downloads | high |
social |
Social media posts, profile updates | medium |
system |
Config changes, restarts, deployments | high |
Configuration
| Class | Auth | Purpose |
|---|---|---|
SynAuthClient(api_key) |
API key (aa_...) |
Agent-facing: request actions, poll status, vault |
SynAuthAdmin(device_id) |
Device ID (dev_...) |
Developer-facing: TOTP, keys, approve/deny |
| Parameter | Default | Description |
|---|---|---|
base_url |
https://synauth.fly.dev |
SynAuth backend URL (override for self-hosted) |
Also Available
- synauth-mcp — MCP server for Claude and other MCP-compatible agents
- SynAuth iOS App — Face ID approval on your iPhone
License
MIT
Release files for synauth 0.2.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 | |
|---|---|---|---|
| synauth-0.2.0.tar.gz | 23.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| synauth-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.8 kB
Release files / synauth-0.2.0.tar.gz
| Download URL | synauth-0.2.0.tar.gz |
|---|---|
| Size | 23.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b7cef171b8fc72b2f39cbc97082e8fddc14d57d0ef1689e9dac3abc23e40aebf
|
|
BLAKE2b-256 checksum How to use checksums |
5864fdc210cd3c41af88d20710aa464ee361dba2a24d0a0abd36263dd6f0f195
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Release files / synauth-0.2.0-py3-none-any.whl
| Download URL | synauth-0.2.0-py3-none-any.whl |
|---|---|
| Size | 15.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
68c7ffa54bd5561e5b90070185a3b930958b5a04ca64b96243c14156c238a248
|
|
BLAKE2b-256 checksum How to use checksums |
a13cc7bf7a0f732b1212b9f3eb4394bab2ec004ffad2219b9ad46953d184b5f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|