# FluentForms → donor lookup APIs FluentForms has no native way to query an external database from a field. These wire it up with a small Custom JS block that calls a secret-gated endpoint on the ticketing backend. Two endpoints are available (same key, CORS, and rate limit): | Endpoint | Purpose | |---|---| | `GET /api/public/donor-eligibility` | Is this email a donor/member? → unlock a discount | | `GET /api/public/ticket-vouchers` | How many free tickets has this donor earned? → 0 / 1 / 2 | Both require `?key=`, are rate-limited (30/min/IP), and CORS-restricted to `PUBLIC_LOOKUP_ORIGIN` (default `https://tickets.beartariacampgrounds.com`). Neither returns names or dollar amounts. The secret is visible in page source, so treat it as deterrence, not security; rotate it by changing `PUBLIC_LOOKUP_SECRET` and redeploying. --- ## Donor discount lookup Unlocks a discount when the entered email belongs to a donor/member. ## Endpoint ``` GET https://scan.beartariacampgrounds.com/api/public/donor-eligibility?key=&email= ``` - `key` = the value of `PUBLIC_LOOKUP_SECRET` (set in the backend `.env`). - Returns minimal JSON — never names or dollar amounts: - `{"eligible": true, "tier": "member"}` - `{"eligible": true, "tier": "donor"}` - `{"eligible": false, "tier": null}` - Rate-limited (30/min/IP) and CORS-restricted to `PUBLIC_LOOKUP_ORIGIN` (default `https://tickets.beartariacampgrounds.com`). > The secret is visible in page source, so treat this as *deterrence, not > security*. It only gates a discount and reveals a yes/no + tier, so the blast > radius is small. Rotate the secret by changing `PUBLIC_LOOKUP_SECRET` and > redeploying. ## Form setup (conditional pricing) The idea: a **hidden field** `donor_tier` holds `regular` / `donor` / `member`. The JS sets it from the email lookup, and your payment options are shown/hidden by FluentForms conditional logic based on its value. 1. **Hidden field.** Add a *Hidden Field*, name it exactly `donor_tier`, default value `regular`. 2. **Email field.** Note its name (default `email`). 3. **Payment options.** Set up two payment items (or two options of a multiple-choice payment field) — a regular price and a discounted price — and give each **conditional logic**: - **Regular price:** show when `donor_tier` **is** `regular` - **Donor price:** show when `donor_tier` **is** `donor` **OR** `donor_tier` **is** `member` (add both rules with "match any"). 4. **Custom HTML.** Add a *Custom HTML* element and paste the snippet below, setting `KEY` to your `PUBLIC_LOOKUP_SECRET` (and `EMAIL_SELECTOR` if your email field isn't named `email`). > FluentForms is Vue-driven, so a plain `input.value = …` won't update its > model and conditional logic won't fire. The snippet uses the native value > setter + dispatches `input`/`change`, which is the reliable way to make FF > notice a programmatic change. Test on your form; if conditional logic still > doesn't react, tell me your FF version and I'll adapt. ## Snippet ```html
``` ## Test ``` curl "https://scan.beartariacampgrounds.com/api/public/donor-eligibility?key=&email=" # donor/member -> {"eligible":true,"tier":"member"} # anyone else -> {"eligible":false,"tier":null} ``` If member and donor get the **same** discounted price, simplify: set the donor price to show when `donor_tier` **is not** `regular`, and you can ignore the member/donor distinction. --- ## Ticket-voucher entitlement Returns how many **free tickets** a donor has earned from their giving, based on donations **on/after a cutoff date** (default `2025-09-04` — "9/4 last year"). ``` GET https://scan.beartariacampgrounds.com/api/public/ticket-vouchers?key=&email= -> {"vouchers": 0} | {"vouchers": 1} | {"vouchers": 2} ``` **Rules** (donations summed on/after the cutoff): | Total since cutoff | Vouchers | |---|---| | ≥ $1000 | 2 | | ≥ $400 | 1 | | otherwise | 0 | **Config** (backend `.env`): | Var | Default | Meaning | |---|---|---| | `VOUCHER_SINCE` | `2025-09-04` | Only donations on/after this date count. Bump each year. | | `VOUCHER_TIER1_MIN` | `400` | Dollar total for 1 voucher | | `VOUCHER_TIER2_MIN` | `1000` | Dollar total for 2 vouchers | > The count is computed from the **dated transaction tables** (online + offline) > — the master-list rollups have no dates. Only `Paid` transactions count. ### Form snippet Displays the voucher count and (optionally) sets a hidden field / caps a quantity. Same pattern as the discount lookup — paste into a Custom HTML element and set `KEY`. ```html
``` ### Test ``` curl "https://scan.beartariacampgrounds.com/api/public/ticket-vouchers?key=&email=" # -> {"vouchers":2} (>= $1000 since the cutoff) ``` > **Heads-up on the cutoff:** with `VOUCHER_SINCE=2025-09-04`, everyone currently > returns `0` because the donation data in NocoDB ends **2025-05-22** — there are > no transactions after the cutoff yet. Adjust `VOUCHER_SINCE` (or wait for new > donations to sync) so the window matches real giving.