Django integration for Lark billing
Project description
django-lark
Django integration for Lark billing.
Installation
pip install django-lark
Quick Start
- Add
django_larkto yourINSTALLED_APPS:
INSTALLED_APPS = [
...
'django_lark',
]
- Configure your Lark API key in
settings.py:
LARK_API_KEY = "lark_api_..."
Or set the LARK_API_KEY environment variable.
- Include the URLs (optional, for customer portal):
urlpatterns = [
...
path('billing/', include('django_lark.urls')),
]
Configuration
All settings are prefixed with LARK_:
| Setting | Default | Description |
|---|---|---|
LARK_API_KEY |
Required | Your Lark API key |
LARK_BASE_URL |
https://api.uselark.ai |
Lark API base URL |
LARK_TIMEOUT |
60.0 |
Request timeout in seconds |
LARK_MAX_RETRIES |
2 |
Max retry attempts |
LARK_USER_SUBJECT_FIELD |
email |
User field to use as external_id |
LARK_AUTO_CREATE_SUBJECTS |
False |
Auto-create Lark subjects for users |
How It Works
django-lark uses Lark's external_id feature to identify users without maintaining a local database mapping. When you create a subject in Lark with an external_id, you can use that same external_id in any API call that accepts a subject_id.
By default, django-lark uses the user's email as the external_id. You can customize this with the LARK_USER_SUBJECT_FIELD setting:
# Use user's primary key
LARK_USER_SUBJECT_FIELD = "id" # Results in "django_user_{pk}"
# Use email (default)
LARK_USER_SUBJECT_FIELD = "email"
# Use a custom field
LARK_USER_SUBJECT_FIELD = "uuid"
# Use a callable for full control
LARK_USER_SUBJECT_FIELD = lambda user: f"myapp_{user.organization_id}_{user.id}"
Usage
Client Access
from django_lark import get_lark_client, get_async_lark_client
# Sync
client = get_lark_client()
subjects = client.subjects.list()
# Async
async def my_view(request):
client = get_async_lark_client()
subjects = await client.subjects.list()
Get External ID for a User
from django_lark.utils import get_external_id_for_user
external_id = get_external_id_for_user(user)
# Use this external_id in any Lark API call
Create Lark Subjects for Users
from django_lark.utils import get_or_create_subject_for_user
# Get or create a Lark subject for a Django user
subject, created = get_or_create_subject_for_user(user)
Check Subscription Status
from django_lark.utils import get_billing_state_for_user
billing_state = get_billing_state_for_user(user)
if billing_state.has_active_subscription:
print("User has active subscription!")
Create Subscriptions
from django_lark.utils import create_subscription_for_user
# Create a subscription and redirect to checkout
response = create_subscription_for_user(
user,
rate_card_id="rc_pro",
success_url="https://example.com/welcome/",
cancelled_url="https://example.com/pricing/",
)
# Check if checkout is required
if response.result.result_type == "requires_action":
return redirect(response.result.action.checkout_url)
else:
# Subscription created directly (e.g., free plan or payment method on file)
subscription = response.result.subscription
# With fixed rate quantities (e.g., seat-based pricing)
subscription = create_subscription_for_user(
user,
rate_card_id="rc_team",
fixed_rate_quantities={"seats": 5},
success_url="https://example.com/welcome/",
)
# With price multipliers (e.g., discounts)
subscription = create_subscription_for_user(
user,
rate_card_id="rc_pro",
rate_price_multipliers={"seats": 0.8}, # 20% discount
success_url="https://example.com/welcome/",
)
Cancel Subscriptions
from django_lark.utils import cancel_subscription, cancel_subscription_for_user
# Cancel by subscription ID (no ownership check)
cancelled = cancel_subscription("sub_abc123")
# Cancel with ownership verification (recommended)
cancelled = cancel_subscription_for_user(user, "sub_abc123")
Change Rate Card (Upgrade/Downgrade)
from django_lark.utils import change_subscription_rate_card, change_subscription_rate_card_for_user
# Change rate card by subscription ID (no ownership check)
response = change_subscription_rate_card(
"sub_abc123",
rate_card_id="rc_enterprise",
success_url="https://example.com/upgraded/",
cancelled_url="https://example.com/plans/",
upgrade_behavior="prorate", # or "rate_difference"
)
# Change with ownership verification (recommended)
response = change_subscription_rate_card_for_user(
user,
"sub_abc123",
rate_card_id="rc_enterprise",
success_url="https://example.com/upgraded/",
)
# Check if checkout is required (e.g., for payment)
if response.result.type == "requires_action":
return redirect(response.result.action.checkout_url)
else:
# Rate card changed directly
subscription = response.result.subscription
The upgrade_behavior parameter controls how charges are calculated:
"prorate"- Customer is charged for the prorated difference based on remaining time"rate_difference"- Customer is charged the full difference between rate cards
View Decorators
from django_lark.decorators import subscription_required
@subscription_required()
def premium_view(request):
return render(request, 'premium.html')
@subscription_required(rate_card_ids=['rc_pro', 'rc_enterprise'])
def pro_view(request):
return render(request, 'pro.html')
@subscription_required(redirect_url='/pricing/')
def feature_view(request):
return render(request, 'feature.html')
Template Tags
{% load lark_tags %}
{% has_active_subscription as is_subscribed %}
{% if is_subscribed %}
<p>Welcome, premium member!</p>
{% else %}
<a href="/pricing/">Upgrade now</a>
{% endif %}
{% has_subscription_to_rate_card "rc_pro" as has_pro %}
{% if has_pro %}
<p>Pro features unlocked!</p>
{% endif %}
{% get_subscriptions as subscriptions %}
{% for sub in subscriptions %}
<p>{{ sub.rate_card_id }} -
<span class="badge {{ sub.status|lark_subscription_status_badge }}">
{{ sub.status }}
</span>
</p>
{% endfor %}
{% get_lark_external_id as external_id %}
Customer Portal
Redirect users to the Lark customer portal:
<a href="{% url 'django_lark:customer_portal' %}?return_url={{ request.path }}">
Manage Subscription
</a>
Checkout
Redirect users to Lark checkout to subscribe to a rate card:
{# Link-based checkout #}
<a href="{% url 'django_lark:checkout' %}?rate_card_id=rc_pro&success_url=/welcome/">
Subscribe to Pro
</a>
{# Form-based checkout #}
<form method="post" action="{% url 'django_lark:checkout' %}">
{% csrf_token %}
<input type="hidden" name="rate_card_id" value="rc_pro">
<input type="hidden" name="success_url" value="/welcome/">
<input type="hidden" name="cancelled_url" value="/pricing/">
<button type="submit">Subscribe</button>
</form>
Change Rate Card
Upgrade or downgrade a user's subscription to a different rate card:
{# Link-based upgrade #}
<a href="{% url 'django_lark:change_rate_card' %}?subscription_id={{ subscription.id }}&rate_card_id=rc_enterprise&success_url=/upgraded/">
Upgrade to Enterprise
</a>
{# Form-based upgrade with proration #}
<form method="post" action="{% url 'django_lark:change_rate_card' %}">
{% csrf_token %}
<input type="hidden" name="subscription_id" value="{{ subscription.id }}">
<input type="hidden" name="rate_card_id" value="rc_enterprise">
<input type="hidden" name="success_url" value="/upgraded/">
<input type="hidden" name="cancelled_url" value="/plans/">
<input type="hidden" name="upgrade_behavior" value="prorate">
<button type="submit">Upgrade Plan</button>
</form>
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_lark-0.2.0.tar.gz.
File metadata
- Download URL: django_lark-0.2.0.tar.gz
- Upload date:
- Size: 20.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3567da2ec86ed1408a828cf7dcf931ab7484a1ac7a999a9224a26d8b9bf63b74
|
|
| MD5 |
ccf995ac4094b70fa1b15c1d9080cee3
|
|
| BLAKE2b-256 |
162067e9b24dc82e0b535364d0a163e9ecaa954c6ea5d66b9fdedf3c05219765
|
Provenance
The following attestation bundles were made for django_lark-0.2.0.tar.gz:
Publisher:
publish.yml on uselark/django-lark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_lark-0.2.0.tar.gz -
Subject digest:
3567da2ec86ed1408a828cf7dcf931ab7484a1ac7a999a9224a26d8b9bf63b74 - Sigstore transparency entry: 845546195
- Sigstore integration time:
-
Permalink:
uselark/django-lark@493a7d513e879dff140f383bfb1be21791ba5505 -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/uselark
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@493a7d513e879dff140f383bfb1be21791ba5505 -
Trigger Event:
release
-
Statement type:
File details
Details for the file django_lark-0.2.0-py3-none-any.whl.
File metadata
- Download URL: django_lark-0.2.0-py3-none-any.whl
- Upload date:
- Size: 16.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f5004ab5d858af9c32bf4f5f76b2b3108b15c5a1f66881005eeabf47f3eb661
|
|
| MD5 |
f5e5526bfd8d8b8f10133dc23e670886
|
|
| BLAKE2b-256 |
94f549d0c802563a6a6899d9b4567453c1b27c9b6ff75387543470e42584ae25
|
Provenance
The following attestation bundles were made for django_lark-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on uselark/django-lark
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_lark-0.2.0-py3-none-any.whl -
Subject digest:
3f5004ab5d858af9c32bf4f5f76b2b3108b15c5a1f66881005eeabf47f3eb661 - Sigstore transparency entry: 845546200
- Sigstore integration time:
-
Permalink:
uselark/django-lark@493a7d513e879dff140f383bfb1be21791ba5505 -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/uselark
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@493a7d513e879dff140f383bfb1be21791ba5505 -
Trigger Event:
release
-
Statement type: