Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Email Funnel AI — Python SDK

Official Python client for the Email Funnel AI integration API. Connect with your project key and secret, then call typed, resource-oriented methods — no manual URLs, headers, or JSON.

  • Python 3.9+
  • Zero dependencies (standard library only)
  • Fully typed, resource-oriented API with full endpoint coverage

Installation

pip install emailfunnelai

Quick start

from emailfunnelai import EmailFunnelAi

client = EmailFunnelAi(
    project_key="pk_your_project_key",
    project_secret="sk_your_secret_key",
)
# base_url defaults to https://app.emailfunnel.ai — pass it only for staging or local dev.

# 1. Confirm your credentials
client.validate()

# 2. Get or create a list
new_list = client.lists.create("Newsletter signups")

# 3. Sync a contact into it
client.contacts.sync(
    {"email": "jane@example.com", "first_name": "Jane", "source_type": "custom_saas"}
).to_list(new_list["id"])

Usage

Every group is an attribute of the client and reads as resource.verb.

Contacts

# Single contact
client.contacts.sync({"email": "jane@example.com", "source_type": "app"}).to_list(list_id)

# Bulk (up to 500; the server queues automatically above 100 rows)
client.contacts.bulk(
    [
        {"email": "a@example.com", "source_type": "import"},
        {"email": "b@example.com", "source_type": "import"},
    ],
    source_type="import",
).to_list(list_id)

# Real-time webhook event
client.contacts.webhook("user.created", {"email": "jane@example.com"}).to_list(list_id)

Lists

client.lists.all()
client.lists.create("My leads", "Optional description")
client.lists.find(list_id)

Bindings

client.bindings.all()
client.bindings.create("custom_crm", list_id, {"sync_enabled": True})
client.bindings.find(binding_id)
client.bindings.update(binding_id, {"sync_enabled": False})
client.bindings.delete(binding_id)
client.bindings.status(binding_id, "completed", errors_count=0)

Field mappings

client.field_mappings.config("custom_crm")
client.field_mappings.for_binding(binding_id).get()
client.field_mappings.for_binding(binding_id).update({"email": "email", "first_name": "fname"})
client.field_mappings.for_binding(binding_id).reset()

Auto-tagging

client.auto_tagging.rules("custom_crm")
client.auto_tagging.preview("custom_crm", {"email": "jane@example.com", "plan": "enterprise"})

Analytics

client.analytics.dashboard()
client.analytics.heatmap({"range": 60, "email_type": "all"})
client.analytics.funnels()
client.analytics.campaigns()
client.analytics.forms()

SSO

client.sso.generate("owner@example.com")  # signed login URL
client.sso.team_members()

Responses & errors

Successful calls return the unwrapped data payload. Any error response raises a typed exception:

from emailfunnelai import ApiError, TransportError

try:
    client.contacts.sync({"email": "invalid"}).to_list(list_id)
except ApiError as error:
    error.status        # 422
    error.error_type    # "validation_error"
    error.messages      # {"contact.email": ["The email field is required."]}
    error.retry_after   # set on 429 rate limits
except TransportError:
    ...  # network / timeout failure (no HTTP response)

Both extend EmailFunnelError, so you can catch that to handle any SDK failure.

Branch on error_type for specific conditions — e.g. a contact list that has been deactivated rejects new members with a 409 list_inactive:

try:
    client.contacts.sync(contact).to_list(list_id)
except ApiError as error:
    if error.error_type == "list_inactive":
        ...  # The target list is inactive — reactivate it or pick another list.

Common error_type values

error_type Status Meaning
invalid_credentials 401 Missing/invalid project key or secret
inactive_project 403 The connected project is inactive
validation_error 422 Request body failed validation (messages set)
invalid_email / suppressed 422 Email is undeliverable or suppressed
list_inactive 409 Target contact list is inactive and rejects new members
rate_limit_exceeded 429 1000 req/hour cap hit (retry_after set)
sync_failed 500 Unexpected sync failure

Custom transport

The client uses urllib by default. Pass any object implementing the HttpClient protocol (e.g. a requests-backed client) to add pooling, proxies, or logging:

client = EmailFunnelAi(project_key=..., project_secret=..., http_client=my_client)

Development

pip install -e ".[dev]"
pytest

Tests mock HTTP and never touch the network. A coverage test asserts the SDK exposes every documented endpoint.

License

MIT © Email Funnel AI

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages