Configure billing
Keep keys on the server. test_ and live_ select mode on the same API host.
Add these values to your project's settings after installation.
import os
VATLY_API_KEY = os.environ["VATLY_API_KEY"]
VATLY_WEBHOOK_SECRET = os.environ["VATLY_WEBHOOK_SECRET"]
VATLY_SCOPE = "my-tenant/my-storefront"
VATLY_REDIRECT_URL_SUCCESS = "https://app.example.com/billing/success"
VATLY_REDIRECT_URL_CANCELED = "https://app.example.com/billing/canceled"
VATLY_PORTAL_REDIRECT_URL = "https://app.example.com/account/billing"
VATLY_CHECKOUTS = {
"book": {"products": [{"id": "one_off_product_example", "quantity": 1}]},
"pro": {"products": [{"id": "subscription_plan_example", "quantity": 1}]},
}
Replace catalog IDs with your own. Offers are an allowlist, not buyer-provided payloads. Products, quantity and redirect destinations stay under server control.
| Setting | Required? | Meaning |
|---|---|---|
VATLY_API_KEY | Yes | May fall back to the environment |
VATLY_SCOPE | Yes | Stable tenant/storefront identity, up to 200 characters |
VATLY_WEBHOOK_SECRET | For webhooks | Secret string or rotation sequence |
VATLY_REDIRECT_URL_SUCCESS, VATLY_REDIRECT_URL_CANCELED | For checkout | HTTPS return destinations |
VATLY_PORTAL_REDIRECT_URL | No | Optional return link in the portal |
VATLY_CHECKOUTS | For checkout | Offer slug → products; optional locale, metadata, billingAddress |
VATLY_BILLABLE_RESOLVER | No | Dotted callable taking request; defaults to request.user |
VATLY_SCOPE_RESOLVER | No | Dotted callable taking request; chooses a trusted scope |
Bill an organization instead of the user
A billable resolver must verify membership before returning a saved team/model. For the default user case, the equivalent resolver is:
from django.core.exceptions import PermissionDenied
def example(request):
if not request.user.is_authenticated:
raise PermissionDenied("Login required")
return request.user
Put your resolver in an importable module and set its dotted path in settings. Never trust a query-string tenant/customer ID as authorization. The facade uses one API key/secret configuration per deployment; scope resolvers alone do not switch credentials. For a multi-credential registry, compose ORMDriver and Fluent explicitly. Webhook routing must also select trusted credentials and scope.