Bento Python Guide

Install the SDK from GitHub, configure BentoAPI with your Site UUID plus API keys, and reuse the client across web requests, jobs, and serverless handlers.

Use the Bento Python SDK to batch events, sync subscribers, and trigger transactional mail from Flask, Django, FastAPI, or any worker queue.

Getting Started

Step 1

Install the Bento Python SDK

Install the SDK with your framework’s package manager and keep it alongside your other HTTP clients so configuration, logging, and credentials stay centralized.

Using PIP

bash
pip install git+https://github.com/bentonow/bento-python-sdk.git

Step 2

Configure the client

Store your Site UUID, publishable key, and secret key in environment variables or a secrets manager. Register the Bento services during your app’s bootstrap so every controller, job, or command reuses the same client.

Client Setup

python
from bento_api import BentoAPI

bento = BentoAPI(
site_uuid='YOUR_SITE_UUID',
username='YOUR_PUBLISHABLE_KEY',
password='YOUR_SECRET_KEY'
)

Beginner Guide

Tracking your first event

Events are the fastest way to add subscribers, kick off automations, and capture context in a single API call. Track onboarding milestones, purchases, or page views, then personalize with Liquid.

  • Pair every event with subscriber metadata so flows can branch without extra imports.
  • Include transactional context (cart items, amounts, IDs) for downstream personalization.
  • Prefer events over bespoke subscriber mutations—automations can add tags or update fields later.
Detail Liquid tag
Product details {{ event.details.product.size }}
Purchase amount {{ event.details.value.amount }}
Transaction ID {{ event.details.unique.key }}
Payment method {{ event.details.value.payment_method }}

Track a simple page view

python
events = [
  {
      'type': '$pageView',
      'email': 'user@example.com',
      'details': {
          'url': '/home',
          'title': 'Home Page'
      }
  }
]

bento.batch_create_events(events)

Track a form submission

python
events = [
    {
        'type': '$formSubmitted',
        'email': 'user@example.com',
        'details': {
            'formName': 'Newsletter Signup',
            'source': 'Homepage'
        }
    }
]

bento.batch_create_events(events)

Managing subscribers

You can still create, tag, or unsubscribe subscribers directly when you need to correct data or build admin tooling. Keep these calls reserved for operational work—events remain the preferred entry point.

Create a new subscriber

python
subscriber = bento.create_subscriber(email='new@example.com')
print(f"New subscriber: {subscriber}")

Tag a subscriber

python
commands = [
    {
      'command': 'add_tag',
      'email': 'user@example.com',
      'query': 'Newsletter'
    }
]

result = bento.execute_commands(commands)
print(f"Command result: {result}")

Unsubscribe A subscriber

python
commands = [
  {
    'command': 'unsubscribe',
    'email': 'user@example.com',
    'query': None
  }
]

result = bento.execute_commands(commands)
print(f"Unsubscribe result: {result}")

Common use cases

  • Track onboarding, purchase, and lifecycle events so automations fire with one API call.
  • Tag subscribers in response to events rather than separate API loops.
  • Store contextual data (cart contents, plan tier) for segmentation and personalization.

Tracking a user login "Event"

python
events = [
  {
    'type': '$login',
    'email': 'user@example.com',
    'details': {
      'method': 'password',
      'device': 'mobile'
    }
  }
]

bento.batch_create_events(events)

Updating user information

python
events = [
  {
    'type': '$activation',
    'email': 'user@example.com',
    'details': {
      'account': 'active',
      'device': 'mobile'
    }
  }
]

bento.batch_create_events(events)

Adding multiple tags to a subscriber

python
subscribers = [
  {
    'email': 'user@example.com',
    'tags': ['Premium', 'Annual Plan', 'Early Adopter']
  }
]

result = bento.batch_create_subscribers(subscribers)
print(f"Batch create result: {result}")

Intermediate Guide

Custom fields and tags

Combine fields for rich profile data with namespaced tags for segmentation. Tags keep audiences organized (`plan:pro`, `status:vip`) while fields store free-form values like locale or favorite product.

Namespaced tag ideas

subscription:basicsubscription:prosubscription:enterprise

Apply via automations whenever possible so marketing and data teams stay in sync.

Create a new custom field definition

python
field = bento.create_field(key='membershipLevel')
print(f"New field: {field}")

Get all existing fields

python
fields = bento.get_fields()
print(f"Fields: {fields}")

Create a new tag

python
tag = bento.create_tag(name='Power User')
print(f"New tag: {tag}")

Get all existing tags

python
tags = bento.get_tags()
print(f"Tags: {tags}")

Tracking purchase events

Always include a `unique` key (order ID, cart token, etc.) so Bento dedupes purchases. Capture cart contents and totals to power LTV reporting and Liquid personalization.

Track a purchase event to monitor customer lifetime value

python
events = [
    {
        'type': '$purchase',
        'email': 'customer@example.com',
        'details': {
            'unique': {
                'key': 'order-123'  # Unique order identifier
            },
            'value': {
                'amount': 9999,  # Amount in cents
                'currency': 'USD'
            },
            'cart': {
                'items': [
                    {
                        'product_id': 'prod-456',
                        'product_name': 'Premium Widget',
                        'product_price': 9999,
                        'quantity': 1,
                        'product_sku': 'SKU-456'
                    }
                ]
            }
        }
    }
]

bento.batch_create_events(events)

Framework quickstarts

Reuse the same BentoAPI client across Flask, Django, or FastAPI routes so every request shares logging and credentials.

Flask

flask_support

python
from flask import Flask, request
from bento_api import BentoAPI

app = Flask(__name__)
bento = BentoAPI(site_uuid="...", username="...", password="...")

@app.route('/signup', methods=['POST'])
def signup():
# Process signup
bento.batch_create_events([{
  'type': '$subscribe',
  'email': request.form['email'],
  'fields': {'source': 'website'}
}])
return "Signup successful!"

Django

django_support

python
# In your views.py
from django.http import HttpResponse
from bento_api import BentoAPI

bento = BentoAPI(site_uuid="...", username="...", password="...")

def track_purchase(request):
# After processing order
bento.batch_create_events([{
  'type': '$purchase',
  'email': request.user.email,
  'details': {'order_id': '123', 'amount': 9999}
}])
return HttpResponse("Order complete!")

FastAPI

fast_api_support

python
from fastapi import FastAPI, Depends
from bento_api import BentoAPI

app = FastAPI()
bento = BentoAPI(site_uuid="...", username="...", password="...")

@app.post("/events/")
async def create_event(event_data: dict):
result = bento.batch_create_events([event_data])
return {"status": "success", "result": result}

Namespaced tags

Reserve tags for segmentation keys (e.g., `product:analytics`). Use fields when you need arbitrary values or timestamps. This keeps your marketing taxonomy predictable.

Advanced Guide

Batch operations

Batch endpoints cover more than 80% of API work. Keep payloads lean, batch 200–300 records, and retry only failed chunks.

Import multiple subscribers at once

python
subscribers = [
    {
        'email': 'user1@example.com',
        'first_name': 'Alice',
        'fields': {'company': 'Acme Inc'}
    },
    {
        'email': 'user2@example.com',
        'first_name': 'Bob',
        'fields': {'company': 'Beta Corp'}
    }
    # ... up to 1,000 subscribers
]

result = bento.batch_create_subscribers(subscribers)
print(f"Batch create subscribers result: {result}")

Import multiple events at once

python
events = [
    {
        'type': '$login',
        'email': 'user@example.com',
        'fields': {'date': '2023-01-01'}
    },
    {
        'type': '$purchase',
        'email': 'user@example.com',
        'details': {
            'unique': {'key': 'order-123'},
            'value': {'currency': 'USD', 'amount': 9999}
        }
    }
    # ... up to 1,000 events
]

bento.batch_create_events(events)

Transactional emails

Great candidates

  • Onboarding confirmation or welcome sequences
  • Password reset and login verification links
  • Payment, receipt, or fulfillment notices
  • Account or compliance notifications

Avoid using transactional for

  • CC / BCC workflows or multi-recipient fan-out
  • Attachments (link to files instead)
  • Marketing, promotional, or newsletter content
  • Bulk announcements where unsubscribes must be honored

Send a transactional email

python
emails = [
    {
        'to': 'recipient@example.com',
        'from': {
            'name': 'Your Name',
            'email': 'sender@example.com'
        },
        'subject': 'Your order #123 has shipped!',
        'html': '<h1>Your order has shipped!</h1><p>We're happy to let you know that your order is on its way.</p>',
        'text': 'Your order has shipped! We're happy to let you know that your order is on its way.'
    }
]

result = bento.batch_create_emails(emails)
print(f"Email send result: {result}")

Subscriber updates

Events remain the preferred way to create and update subscribers—they trigger flows and can mutate tags or fields downstream. Use direct endpoints when workflows demand determinism.

Events-first creation

Create a subscriber when they sign up

python
events = [
  {
    'type': '$subscribe',
    'email': 'new-user@example.com',
    'fields': {
      'firstName': 'Jane',
      'lastName': 'Doe',
      'signupSource': 'website'
    }
  }
]

bento.batch_create_events(events)

Create a subscriber when they make a purchase

python
events = [
  {
    'type': '$purchase',
    'email': 'customer@example.com',
    'details': {
    'unique': {'key': 'order-123'},
    'value': {'amount': 9999, 'currency': 'USD'}
  },
    'fields': {
      'firstName': 'John',
      'lastName': 'Smith',
      'customerType': 'new'
    }
  }
]

bento.batch_create_events(events)

Direct creation options

Create a single subscriber (email only)

python
subscriber = bento.create_subscriber(email='user@example.com')
print(f"New subscriber: {subscriber}")

Import multiple subscribers

python
subscribers = [
  {
    'email': 'user1@example.com',
    'fields': {
      'membershipTier': 'gold',
      'accountStatus': 'active',
      'lastRenewalDate': '2023-01-01T00:00:00'
    }
  },
  {
    'email': 'user2@example.com',
    'fields': {
      'membershipTier': 'silver',
      'accountStatus': 'pending',
      'trialEndsAt': '2023-02-01T00:00:00'
    }
  }
]

result = bento.batch_create_subscribers(subscribers)
print(f"Batch create subscribers result: {result}")

Event-driven profile updates

Update subscriber when they update their profile

python
events = [
    {
        'type': '$subscription_change',
        'email': 'user@example.com',
        'fields': {
            'subscriptionTier': 'premium'
        }
    }
]

bento.batch_create_events(events)

Single attribute tweaks

Add or update a single field

python
subscribers = [
  {
    'email': 'user2@example.com',
    'first_name': 'Jesse',
    'last_name': 'Bento',
    'tags': ['membership:premium'],
    'fields': {
      'membershipTier': 'premium',
      'accountStatus': 'pending',
      'trialEndsAt': '2023-02-01T00:00:00'
    }
  }
]

result = bento.batch_create_subscribers(subscribers)
print(f"Update result: {result}")

Add a tag

python
subscribers = [
  {
    'email': 'user2@example.com',
    'first_name': 'Jesse',
    'last_name': 'Bento',
    'tags': ['example:tag']
  }
]

result = bento.batch_create_subscribers(subscribers)
print(f"Add tag result: {result}")

Remove a field

python
commands = [
  {
    'command': 'remove_field',
    'email': 'user@example.com',
    'query': 'temporaryStatus'
  }
]

result = bento.execute_commands(commands)
print(f"Remove field result: {result}")

Batch updates

Update multiple subscribers

python
subscribers = [
  {
    'email': 'user1@example.com',
    'fields': {
      'membershipTier': 'gold',
      'accountStatus': 'active',
      'lastRenewalDate': '2023-01-01T00:00:00'
    }
  },
  {
    'email': 'user2@example.com',
    'fields': {
      'membershipTier': 'silver',
      'accountStatus': 'pending',
      'trialEndsAt': '2023-02-01T00:00:00'
    }
  }
]

result = bento.batch_create_subscribers(subscribers)
print(f"Batch update result: {result}")

Specialized operations

Change a subscribers email address

python
commands = [
  {
    'command': 'change_email',
    'email': 'old@example.com',
    'query': 'new@example.com'
  }
]

result = bento.execute_commands(commands)
print(f"Change email result: {result}")

Update all fields at once

python
subscribers = [
  {
    'email': 'user@example.com',
    'first_name': 'Updated',
    'last_name': 'Name',
    'fields': {
      'address': {
        'street': '123 Main St',
        'city': 'New York',
        'state': 'NY',
        'zip': '10001'
      },
      'preferences': {
        'theme': 'dark',
        'notifications': True
      }
    }
  }
]

result = bento.batch_create_subscribers(subscribers)
print(f"Update all fields result: {result}")

Unsubscribe a user

python
commands = [
  {
    'command': 'unsubscribe',
    'email': 'user@example.com',
    'query': None
  }
]

result = bento.execute_commands(commands)
print(f"Unsubscribe result: {result}")

Utility features

Validate addresses, guess gender, geolocate IPs, or check blacklists without integrating third-party APIs. These helpers are rate-limited—cache responses when you can.

Validate Email

python
validation_result = bento.validate_email(
  email='user@example.com',
  name=None,
  user_agent='Mozilla/5.0...',
  ip='192.168.1.1'
)

print(f"Email validation result: {validation_result}")

Guess Prediction (for personalization)

python
gender_info = bento.guess_gender(name='Alex')
      print(f"Gender prediction result: {gender_info}")

Geolocate IP Address

python
location = bento.geolocate_ip(ip='208.67.222.222')
print(f"IP geolocation result: {location}")

Check Domain/IP blacklist

python
domain_blacklist_info = bento.check_blacklist(domain='example.com')
print(f"Domain blacklist check result: {domain_blacklist_info}")

# Or check an IP instead
ip_blacklist_info = bento.check_blacklist(ip='192.168.1.1')
print(f"IP blacklist check result: {ip_blacklist_info}")

API Reference

The Python SDK mirrors Bento's REST resources—most services expose async methods for batch operations plus convenience helpers for validation.

Batch helpers

Troubleshooting

Not Authorized

Verify publishable + secret keys and ensure the team member still has access.

Rate Limited

Implement exponential backoff for batch operations and honor Retry-After headers.

Network Errors

Confirm outbound traffic can reach app.bentonow.com and retry transient socket resets.

Payload Exceptions

Double-check Author emails and ensure payloads match the documented schema.

Debugging tips

  1. Store Site UUID and API keys in environment variables or a secrets manager, then inject them when instantiating BentoAPI.
  2. Catch `BentoAPIError` (or generic exceptions) to log response payloads and retry transient errors with libraries like `tenacity`.
  3. Break bulk imports into 200–300 record batches and dispatch them through Celery/RQ workers so retries stay isolated.

FAQ

Can I use this SDK in a frontend environment?

No. The Python SDK requires your publishable key, secret key, and Site UUID, so it must stay on the server. Use the JavaScript SDK or proxy calls through your backend for browser tracking.

How do I handle rate limiting?

Wrap calls with a retry policy (e.g., `tenacity`) that honors `Retry-After` headers so hot jobs back off automatically instead of failing.

rate_limiting

python
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10))
def perform_bento_api_call():
# Your Bento API calls here
bento.batch_create_subscribers(subscribers)
What's the maximum batch size for importing subscribers or events?

Up to 1,000 subscribers or events per payload are supported, but 200–300 keeps payloads fast to retry. Use queues like Celery for large backfills.

max_batch_size

python
# Split large subscriber lists into smaller chunks
def chunk_list(data, chunk_size=300):
for i in range(0, len(data), chunk_size):
yield data[i:i + chunk_size]

# Process each chunk as a separate task
for chunk in chunk_list(all_subscribers, 300):
process_subscriber_chunk.delay(chunk)

# In your Celery task
@app.task
def process_subscriber_chunk(subscribers):
bento.batch_create_subscribers(subscribers)
How do I track anonymous users?

Every event currently needs an email address. Capture emails early (waitlists, checkout, gated content) and hydrate events once the email is known.

Which Python versions are supported?

Python 3.6+ works, though we recommend 3.10 or newer for better async performance and TLS defaults. The SDK depends on `requests` under the hood.

How can I contribute to the SDK?

Open issues or pull requests on github.com/bentonow/bento-python-sdk and share feedback in the Bento community Discord.

Can I use the SDK with AWS Lambda or other serverless environments?

Yes. Instantiate BentoAPI outside the handler so sockets are reused, and keep payloads lean to avoid cold-start penalties.

serverless_support

python
# Initialize the client outside the handler function
bento = BentoAPI(
site_uuid=os.environ['BENTO_SITE_UUID'],
username=os.environ['BENTO_PUBLISHABLE_KEY'],
password=os.environ['BENTO_SECRET_KEY']
)

def lambda_handler(event, context):
# Use the existing client for better performance
result = bento.batch_create_events(event['events'])
return {"statusCode": 200, "body": json.dumps(result)}
How does the Python SDK integrate with common web frameworks?

Initialize BentoAPI once (app factory, ASGI lifespan, etc.) and reuse it inside Flask blueprints, Django views, or FastAPI routers—see the framework quickstarts below for drop-in snippets.

Contribute or debug further

The Python SDK is open source. Report bugs, request features, or open pull requests at https://github.com/bentonow/bento-python-sdk. Keep your local tooling on Python 3.8+ (requests-based client) to match production builds.

Need the original Markdown? Open raw file