# Referral quickstart: Django

The tag in your base template, a middleware that keeps the code, and each signup reported from its view.

Referrals in a Django app: the tag in your base template, the partner's code
kept by your own server, every signup reported as a lead, and sales from your
billing system.

## Before you start

- A key with the **Referral tracking** preset (the single scope
  `conversions:write`), made under **Settings, Developers**. Keep it on your
  server as `BOLTCLAW_API_KEY`, never in a browser or an app.
- The program's id, on its **Setup** tab, as `BOLTCLAW_PROGRAM_ID`.

## 1. Put the tag on your site

Add the version 2 tag to every page, in your root layout or template. It keeps a
partner's code from `?via=<code>` in a first-party cookie on your own domain,
`bc_ref`, for the program's cookie window, and gives you
`BoltClawReferral.code()` in the browser.

```html
<script src="https://boltclaw.ai/referrals/v2.js" defer data-payment-links="auto"></script>
```

`data-payment-links="auto"` is only for Stripe Payment Links and the Buy Button;
`data-welcome="auto"` adds the friend's welcome. The tag makes no request at all
unless the welcome is on and the visitor arrived with a code.

## 2. Keep the code from your server

A middleware sets `bc_ref` from `?via=` in your own response.

```python
# referrals/middleware.py
import re

code_shape = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$")
cookie_days = 30  # the program's cookie window (30 days unless you changed it)

class KeepReferral:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        code = request.GET.get("via", "")
        if 3 <= len(code) <= 40 and code_shape.match(code):
            response.set_cookie("bc_ref", code, max_age=cookie_days * 86400, samesite="Lax", secure=True, httponly=False)
        return response
```

Add `"referrals.middleware.KeepReferral"` to `MIDDLEWARE`. For partner links that
open straight on your site, you may also report the visit with
`POST /v1/referrals/clicks` (`code`, `ip`, `user_agent`, `referrer`): Bolt Claw
hashes and classes them and stores neither, and a click earns nothing by itself.

**Why set the cookie from your server.** Safari deletes a cookie a script
created once the visitor has gone 7 days of browsing without using your site,
and keeps one only 24 hours on a page reached through a tracking link, so a
code the tag keeps can be gone a week later. A cookie your OWN server sets in
its response keeps its full lifetime, unless it comes through somebody else's
host (a third-party CNAME or IP address), which Safari caps at 7 days
(WebKit's published tracking prevention rules, read 2026-10-23). Setting `bc_ref`
from your server, not `HttpOnly`, keeps the full window and the tag still reads
it.

## 3. Report each signup as a lead

In the view that creates the account, with your own id for the person:

```python
# referrals.py
import json, os, urllib.request

def report_conversion(body):
    body = {"program_id": os.environ["BOLTCLAW_PROGRAM_ID"], **body}
    request = urllib.request.Request(
        "https://api.boltclaw.ai/v1/referrals/conversions",
        data=json.dumps(body).encode(),
        headers={"Authorization": "Bearer " + os.environ["BOLTCLAW_API_KEY"], "Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(request, timeout=10) as response:
        return json.load(response)
```

```python
# views.py
from .referrals import report_conversion

def signup(request):
    user = create_user(request)  # your own code
    code = request.COOKIES.get("bc_ref")
    report_conversion({
        "event": "lead",
        "event_id": f"signup-{user.pk}",
        "customer": {"id": str(user.pk)},
        **({"referral": {"code": code}} if code else {}),
    })
    return redirect("welcome")
```

`event_id` is the idempotency key: a retry after a timeout changes nothing.

## 4. Record sales

Connect the billing system you take payments with on the **Setup** tab (see
[Connect your billing system](https://boltclaw.ai/docs/referral-setup)), and pass the code to checkout
as its guide shows: sales, renewals and refunds are then reported for you, and
the setup status ticks them off. Not on one of the twelve? Report each sale from
your server with `event: "sale"`, your own `event_id` for the payment, the same
`customer.id` as the signup, `amount` in minor units and `currency`.

## 5. Send a test sale

Press **Send a test sale** on the Setup tab: a click, a signup, a sale with two
items and a partial refund go through your real rules as test data, credited to
the program's test partner, never paid and never counted. To check your own
wiring, send one of your own conversions with `"test": true`: it is test data
too, and **Clear test data** deletes it all. The setup status's rows turn green
only for live events.

<!-- https://boltclaw.ai/docs/referral-quickstart-django as markdown. Generated from openapi.yaml; API version 1.22.0. -->
<!-- Every /docs page answers as markdown: add .md to its path, or send Accept: text/markdown. -->
